﻿using System;
using System.Collections.Generic;
using System.IO;

using CourseDesign_02;

namespace FundamentalsOfCompiling
{
    class WordParser
    {
        //reservedWords用来保存保留字和其相应的词法类型
        ReservedTable[] reservedWords = { 
	    new ReservedTable("program",LexType.PROGRAM),
	    new ReservedTable("type",LexType.TYPE),
	    new ReservedTable("var",LexType.VAR),
	    new ReservedTable("procedure",LexType.PROCEDURE),
	    new ReservedTable("begin",LexType.BEGIN),
	    new ReservedTable("end",LexType.END),
	    new ReservedTable("array",LexType.ARRAY),
	    new ReservedTable("of",LexType.OF),
	    new ReservedTable("record",LexType.RECORD),
	    new ReservedTable("if",LexType.IF),
	    new ReservedTable("then",LexType.THEN),
	    new ReservedTable("else",LexType.ELSE),
	    new ReservedTable("fi",LexType.FI),
	    new ReservedTable("while",LexType.WHILE),
	    new ReservedTable("do",LexType.DO),
	    new ReservedTable("endwh",LexType.ENDWH),
	    new ReservedTable("read",LexType.READ),
	    new ReservedTable("write",LexType.WRITE),
	    new ReservedTable("return",LexType.RETURN),
	    new ReservedTable("integer",LexType.INTEGER),
	    new ReservedTable("char",LexType.CHAR1)
	    };
      //  private StreamReader source = null;

        // private StreamReader sout = null;
        private string tokenString = null;
      //  private string lineBuf = null;//一行字符串
       // private int length;//buffer的长度
       // private int linepos = 0;//字符串的指针，标识处理位置
       // private bool EOF_flag;//表示文件结束
        private Global global;
        private ISource source = null;
        private List<TokenType> list;//存储token序列的链表

        public List<TokenType> getList() { return list; }

       // MainWindow window;
        public WordParser(Global g, ISource s,List<TokenType>list)
        {
            this.global = g;
           // linepos = 0;
            //EOF_flag = false;
            global.operateError = false;
            global.operateTokentnum = 0;
            global.operatelineno = 0;
           // length = 0;
            this.list = list;
            this.source = s;
            //  sin = new StreamReader(path);
            // window = mainWindow;
        }

        public void getTokenList()
        {
            global.operatelineno = 0;
           // linepos = 0;
           // length = 0;
            global.operateTokentnum = 0;
           // EOF_flag = false;
            global.operateError = false;
           // source = new StreamReader(path);
            //if (source == null)
            //{
            //    //window.WriteLine("未找到源文件");
            //    global.operateError = true;
            //    throw 
            //}

            TokenType currentToken = new TokenType();
            do
            {
                StateType state = StateType.START;
                bool save;
                tokenString = "";
                while (state != StateType.DONE)
                {
                    int c = source.getNextChar();
                    save = true;
                    switch (state)
                    {
                        case StateType.START:
                            if (isdigit(c))
                                state = StateType.INNUM;

                            else if (isalpha(c))
                                state = StateType.INID;
                            else if (c == ':')
                                state = StateType.INASSIGN;

                            else if (c == '.')
                                state = StateType.INRANGE;

                            else if (c == '\'')
                            {
                                save = false;
                                state = StateType.INCHAR;
                            }

                            else if ((c == ' ') || (c == '\t'))
                            {
                                save = false;
                            }
                            else if ((c == '\n'))
                            {
                                save = false;// Window.WriteLine("2222222222222");
                                global.operatelineno = global.operatelineno + 1;
                                if (global.operateTokentnum > 0)
                                {
                                    TokenType tokenline = new TokenType();
                                    tokenline.lineshow = 0;
                                    tokenline.Lex = LexType.CRT;//存储一个换行符号
                                    tokenline.Sem = "\n";
                                    list.Add(tokenline);
                                    global.operateTokentnum = global.operateTokentnum + 1;
                                }
                            }
                            else if (c == '{')
                            {
                                save = false;
                                state = StateType.INCOMMENT;
                            }
                            else
                            {
                                state = StateType.DONE;
                                switch (c)
                                {
                                    case -1://-1表示文件结束
                                        save = false;
                                        currentToken.Lex = LexType.ENDFILE1;//表示文件结束
                                        break;

                                    case '=':
                                        currentToken.Lex = LexType.EQ;
                                        break;

                                    case '<':
                                        currentToken.Lex = LexType.LT;
                                        break;

                                    case '+':
                                        currentToken.Lex = LexType.PLUS;
                                        break;

                                    case '-':
                                        currentToken.Lex = LexType.MINUS;
                                        break;

                                    case '*':
                                        currentToken.Lex = LexType.TIMES;
                                        break;

                                    case '/':
                                        currentToken.Lex = LexType.OVER;
                                        break;
                                    case '[':
                                        currentToken.Lex = LexType.LMIDPAREN;
                                        break;
                                    case ']':
                                        currentToken.Lex = LexType.RMIDPAREN;
                                        break;
                                    case '(':
                                        currentToken.Lex = LexType.LPAREN;
                                        break;

                                    case ')':
                                        currentToken.Lex = LexType.RPAREN;
                                        break;

                                    case ';':
                                        currentToken.Lex = LexType.SEMI;
                                        break;
                                    case ',':
                                        currentToken.Lex = LexType.COMMA;
                                        break;
                                    default:
                                        currentToken.Lex = LexType.ERROR1;
                                        global.operateError = true;
                                        break;
                                }
                            }//里层的switch
                            break;
                        case StateType.INCOMMENT:
                            save = false;
                            if (c == -1)
                            {
                                state = StateType.DONE;
                                currentToken.Lex = LexType.ENDFILE1;

                            }
                            else if (c == '}') state = StateType.START;
                            break;
                        case StateType.INASSIGN:
                            state = StateType.DONE;
                            if (c == '=')
                                currentToken.Lex = LexType.ASSIGN;
                            else
                            {
                                source.ungetNextChar();
                                save = false;
                                currentToken.Lex = LexType.COLON;
                            }
                            break;

                        case StateType.INRANGE:
                            state = StateType.DONE;
                            if (c == '.')
                                currentToken.Lex = LexType.UNDERANGE;
                            else
                            {
                                source.ungetNextChar();
                                save = false;
                                currentToken.Lex = LexType.DOT;
                            }
                            break;

                        case StateType.INNUM:

                            if (!isdigit(c))
                            {
                                source.ungetNextChar();
                                save = false;
                                state = StateType.DONE;
                                currentToken.Lex = LexType.INTC;
                            }
                            break;
                        case StateType.INCHAR:

                            if (isalnum(c))
                            {
                                int c1 = source.getNextChar();
                                if (c1 == '\'')
                                {
                                    save = true;
                                    state = StateType.DONE;
                                    currentToken.Lex = LexType.CHARC;
                                }
                                else
                                {
                                    source.ungetNextChar();
                                    source.ungetNextChar();
                                    //save = TRUE;
                                    state = StateType.DONE;
                                    currentToken.Lex = LexType.ERROR1;
                                    global.operateError = true;
                                }
                            }
                            else
                            {
                                source.ungetNextChar();
                                //save = TRUE;
                                state = StateType.DONE;
                                currentToken.Lex = LexType.ERROR1;
                                global.operateError = true;
                            }
                            break;
                        case StateType.INID:
                            if (!isalnum(c))
                            {
                                source.ungetNextChar();
                                save = false;
                                state = StateType.DONE;
                                currentToken.Lex = LexType.ID;
                            }
                            break;
                        case StateType.DONE: break;

                        default:
                            //window.WriteLine("Scanner Bug: state= " + state + "\n");
                            state = StateType.DONE;
                            currentToken.Lex = LexType.ERROR1;
                            global.operateError = true;
                            break;
                    }//第一层switch
                    if (save)
                        tokenString += (char)c;
                    if (state == StateType.DONE)
                    {
                        if (currentToken.Lex == LexType.ID)
                        {
                            currentToken.Lex = reservedLookup(tokenString);
                        }
                    }
                }//while
                currentToken.lineshow = global.operatelineno;
                currentToken.Sem = tokenString;
                list.Add(currentToken);
                global.operateTokentnum = global.operateTokentnum + 1;
                //Window.WriteLine("tokenString :"+tokenString);
                tokenString = "";
            } while ((currentToken.Lex) != LexType.ENDFILE1);
            //window.WriteLine("end of get token list");
            Console.WriteLine("close file");
            source.close();

        }

        public  void printTokenList(Midiator midiator)
        {
           // midiator.WriteLine("输出TokenList（即是list）中信息");
            int num;
            TokenType currentToken;
            //if (global.operateError)
            //    midiator.WriteLine("----词法分析有错，以ERROR打头的为错误的Token：\n");
            //else midiator.WriteLine("----词法分析无错：Token序列如下：\n");
            int count = list.Count;
            if (count <= 0)
            {
                //midiator.WriteLine("Token序列为空");
                return;
            }
            for (num = 0; num <count; num++)
            {
                currentToken = list[num];
                midiator.Write(currentToken);
               // printToken(midiator, currentToken);
            }
        }

        //private  void printToken(Midiator midiator, TokenType token)
        //{
        //    switch (token.Lex)
        //    {
        //        case LexType.PROGRAM:
        //        case LexType.PROCEDURE:
        //        case LexType.TYPE:
        //        case LexType.VAR:
        //        case LexType.IF:
        //        case LexType.THEN:
        //        case LexType.ELSE:
        //        case LexType.FI:
        //        case LexType.WHILE:
        //        case LexType.DO:
        //        case LexType.ENDWH:
        //        case LexType.BEGIN:
        //        case LexType.END:
        //        case LexType.READ:
        //        case LexType.WRITE:
        //        case LexType.ARRAY:
        //        case LexType.OF:
        //        case LexType.RECORD:
        //        case LexType.RETURN:
        //        case LexType.INTEGER:
        //        case LexType.CHAR1:
        //            midiator.WriteLine("reserved word: " + token.Sem);
        //            break;
        //        case LexType.ASSIGN: midiator.WriteLine(":="); break;

        //        case LexType.LT: midiator.WriteLine("<"); break;

        //        case LexType.EQ: midiator.WriteLine("="); break;

        //        case LexType.PLUS: midiator.WriteLine("+"); break;

        //        case LexType.MINUS: midiator.WriteLine("-"); break;

        //        case LexType.TIMES: midiator.WriteLine("*"); break;

        //        case LexType.OVER: midiator.WriteLine("/"); break;

        //        case LexType.LPAREN: midiator.WriteLine("("); break;

        //        case LexType.RPAREN: midiator.WriteLine(")"); break;

        //        case LexType.LMIDPAREN: midiator.WriteLine("["); break;

        //        case LexType.RMIDPAREN: midiator.WriteLine("]"); break;

        //        case LexType.SEMI: midiator.WriteLine(";"); break;

        //        case LexType.COLON: midiator.WriteLine(":"); break;

        //        case LexType.COMMA: midiator.WriteLine(","); break;

        //        case LexType.DOT: midiator.WriteLine("."); break;

        //        case LexType.UNDERANGE: midiator.WriteLine(".."); break;

        //        case LexType.ENDFILE1: midiator.WriteLine("EOF"); break;

        //        case LexType.INTC:
        //            midiator.WriteLine("INTC, val= " + token.Sem);
        //            break;

        //        case LexType.CHARC:
        //            midiator.WriteLine("CHARC, letter= " + token.Sem);
        //            break;

        //        case LexType.ID:
        //            midiator.WriteLine("ID, name= " + token.Sem);
        //            break;

        //        case LexType.ERROR1:
        //            midiator.WriteLine("ERROR:" + token.Sem);
        //            break;
        //        case LexType.CRT:
        //            midiator.WriteLine("记录的是换行符号");
        //            break;
        //        default:
        //            midiator.WriteLine("Unknown token:" + token.Lex);
        //            break;
        //    }
        //} 
        //protected int getNextChar()
        //{
        //    if (!(linepos < length))
        //    {
        //        global.operatelineno = global.operatelineno + 1;
        //        if (global.operateTokentnum > 0)
        //        {
        //            TokenType tokenline = new TokenType();
        //            tokenline.lineshow = 0;
        //            tokenline.Lex = LexType.CRT;//存储一个换行符号
        //            tokenline.Sem = "\n";
        //            list.Add(tokenline);
        //            global.operateTokentnum = global.operateTokentnum + 1;
        //        }

        //        if ((lineBuf = source.ReadLine()) != null)
        //        {
        //            lineBuf = "   " + lineBuf;
        //            // Window.WriteLine("buffer "+lineBuf);
        //            length = lineBuf.Length;
        //            //Window.WriteLine("buffer length :"+length);
        //            linepos = 0;
        //            return lineBuf[linepos++];
        //        }
        //        else
        //        {
        //            EOF_flag = true;
        //            return -1;
        //        }
        //    }
        //    else return lineBuf[linepos++];
        //}

        //protected void ungetNextChar()
        //{//将字符重新放回缓冲区中
        //    if (!EOF_flag)
        //        linepos--;
        //}
        
       
        protected LexType reservedLookup(String str)
        {
            int i;
            for (i = 0; i < reservedWords.Length; i++)
                if (reservedWords[i].str.Equals(str))
                    return (reservedWords[i].tok);
            return LexType.ID;
        }
        protected bool isdigit(int i)
        {
            if (i >= 48 && i <= 57) return true;
            else return false;
        }
        protected bool isalpha(int c)
        {
            if ((c >= 65 && c <= 90) || (c >= 97 && c <= 122)) return true;
            else return false;
        }
        protected bool isalnum(int c)
        {
            bool flag;
            flag = isdigit(c);
            if (flag == false)
                flag = isalpha(c);
            return flag;
        }
    }
}
